import { Injectable } from '@angular/core'
import { NzTreeNode } from 'ng-zorro-antd'
import { Menu } from '@delon/theme'

import { IMenu } from '@shared/interfaces/role'
import { EMenuType } from '@shared/enums'

@Injectable({
  providedIn: 'root',
})
export class TreeService {
  constructor() {}

  computeMenuTree(input: IMenu[]): Menu[] {
    if (!input) {
      return []
    }
    const menuMap: { [key: string]: Menu } = {}
    const menus = input
      .filter(m => this.isMenu(m))
      .map(m => {
        const item: Menu = {
          text: m.menuName,
          link: m.menuUri,
          i18n: m.menuState ? m.menuState.toUpperCase() : '',
          level: m.level,
          ordinal: m.ordinal,
        }

        if (m.menuIcon) {
          item.icon = {
            type: 'iconfont',
            iconfont: m.menuIcon,
          }
        }

        menuMap[m.ordinal] = item
        return item
      })

    if (menus.length === 0) {
      return []
    }

    const head = menus[0]
    const size = menus.length
    let i = 1
    let previousLevel = head.level
    menuMap[head.ordinal] = head

    while (i < size) {
      const { ordinal, level } = menus[i]
      const current = menuMap[ordinal]
      const previous = menuMap[menus[i - 1].ordinal]

      if (level === 1) {
      } else if (level > previousLevel) {
        // 当前节点为前一个节点的孩子
        current.parentOrdinal = previous.ordinal
        previous.children = previous.children || []
        previous.children.push(current)
      } else if (level === previousLevel) {
        // 当前节点为前一个节点的兄弟
        const parent = menuMap[previous.parentOrdinal]
        current.parentOrdinal = parent.ordinal
        parent.children.push(current)
      } else {
        // 当前节点为前一个节点的叔叔
        const sibling = menuMap[previous.parentOrdinal]
        const parent = menuMap[sibling.parentOrdinal]
        current.parentOrdinal = parent.ordinal
        parent.children.push(current)
      }

      previousLevel = current.level
      i++
    }

    return Object.values(menuMap)
      .map(m => {
        if (m.children && m.children.length) {
          m.hideInBreadcrumb = true
          m.group = true
        }

        return m
      })
      .filter(m => m.level === 1)
  }

  createTree(menus: IMenu[]): NzTreeNode[] {
    const nodes: NzTreeNode[] = menus.map(m => {
      const node = new NzTreeNode({
        title: `${m.menuName}:${m.menuUri}`,
        key: `${m.ordinal}`,
        origin: m,
        isLeaf: true,
        menuId: m.menuId,
      })

      return node
    })
    const tree: NzTreeNode[] = []
    const size = menus.length
    let i = 0
    let previousLevel = 1
    while (i < size) {
      try {
        const node = nodes[i]
        const level = node.origin.origin.level
        const previous = nodes[i - 1]
        let parent: NzTreeNode
        if (level === 1) {
          node.level = 0
          tree.push(node)
        } else if (level > previousLevel) {
          // 当前节点为前一个节点的孩子
          // previous.isExpanded = false
          previous.isLeaf = false
          node.parentNode = previous
          node.level = previous.level + 1
          previous.children = [node]
        } else if (level === previousLevel) {
          // 当前节点为前一个节点的兄弟
          parent = previous.parentNode
          node.parentNode = parent
          node.level = parent.level + 1
          parent.children.push(node)
        } else {
          // 当前节点为前一个节点的叔叔
          parent = previous.parentNode.parentNode
          node.parentNode = parent
          node.level = parent.level + 1
          parent.children.push(node)
        }
        previousLevel = level
      } catch (err) {
        console.log('error at', i)
      } finally {
        i++
      }
    }

    return tree
  }

  // 广度优先遍历
  dfs(nodes: NzTreeNode[]): number[] {
    const result: number[] = []
    const stack: NzTreeNode[] = []
    stack.push(...nodes)
    while (stack.length) {
      const node = stack.pop()
      result.push(node.origin.menuId)
      if (node.children && node.children.length) {
        stack.push(...node.children)
      }
    }
    return result
  }

  // 前序遍历
  preOrderTraverse(nodes: NzTreeNode[]): NzTreeNode[] {
    if (!nodes.length) {
      return []
    }

    const result: NzTreeNode[] = []
    const stack: NzTreeNode[] = nodes.slice(0)

    while (stack.length) {
      const node = stack.shift()
      if (node.children.length) {
        stack.unshift(...node.children.slice(0))
      }
      result.push(node)
    }

    return result
  }

  private isMenu(menu: IMenu): boolean {
    const type = menu.menuStatus
    return type === EMenuType.Menu || type === EMenuType.CommonMenu
  }
}
